'use client';

import { useState, useEffect, useCallback, useRef } from 'react';
import * as signalR from '@microsoft/signalr';
import { fetchApi } from '@/lib/utils/client';
import { useStudioContext } from '@/app/studio/context';
import { useSignalRContext } from '@/contexts/signalrProvider';
import type { CrewMemberItem, CrewMemberListResponse, SearchResultItem, SearchMemberResponse } from '@/types/response/crew/member';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@/components/ui/tooltip';
import { Info } from 'lucide-react';

function RequiredLabel({ htmlFor, children }: { htmlFor: string; children: React.ReactNode }) {
	return <Label htmlFor={htmlFor}><span className="text-destructive mr-0.5">*</span>{children}</Label>;
}

const EMPTY_MEMBER_FORM = {
	nickname: '',
	role: '',
	sortOrder: 0,
	isActive: true
};

type Props = {
	crewID: number;
};

export default function CrewMembersTab({ crewID }: Props)
{
	const { channelID } = useStudioContext();
	const { appConnection, appConnected } = useSignalRContext();
	const [members, setMembers] = useState<CrewMemberItem[]>([]);
	const [loading, setLoading] = useState(true);

	// 초대 코드
	const [inviteCode, setInviteCode] = useState<string|null>(null);
	const [generatingCode, setGeneratingCode] = useState(false);

	// 회원 검색
	const [searchQuery, setSearchQuery] = useState('');
	const [searchResults, setSearchResults] = useState<SearchResultItem[]>([]);
	const [showSearch, setShowSearch] = useState(false);
	const searchTimer = useRef<ReturnType<typeof setTimeout>|null>(null);

	// 크루원 편집 모달
	const [editModal, setEditModal] = useState<{ open: boolean; member: CrewMemberItem|null }>({ open: false, member: null });
	const [editForm, setEditForm] = useState(EMPTY_MEMBER_FORM);
	const [saving, setSaving] = useState(false);

	const fetchMembers = useCallback(async () => {
		try {

			const res = await fetchApi<CrewMemberListResponse>(`/api/studio/crew/member/list/${crewID}`);
			setMembers(res.data?.list ?? []);

		} catch {

		} finally {
			setLoading(false);
		}
	}, [crewID]);

	useEffect(() => { fetchMembers(); }, [fetchMembers]);

	// SignalR 멤버 변경 이벤트 수신 — 운영자 그룹(crew:{crewID}) 구독 + 200ms debounce refetch.
	// 다중 이벤트(예: 일괄 작업) 시 한 번만 refetch 하도록 합침.
	useEffect(() => {
		if (!appConnection || !appConnected) {
			return;
		}

		if (appConnection.state !== signalR.HubConnectionState.Connected) {
			return;
		}

		let refetchTimer: ReturnType<typeof setTimeout>|null = null;
		const scheduleRefetch = () => {
			if (refetchTimer) {
				clearTimeout(refetchTimer);
			}
			refetchTimer = setTimeout(() => {
				fetchMembers();
			}, 200);
		};

		const handler = (_payload: unknown) => {
			scheduleRefetch();
		};

		appConnection.on('ReceiveCrewMemberChange', handler);
		appConnection.invoke('JoinCrew', crewID).catch(err => {
			console.warn('[crew] JoinCrew failed:', err);
		});

		return () => {
			if (refetchTimer) {
				clearTimeout(refetchTimer);
			}
			appConnection.off('ReceiveCrewMemberChange', handler);

			if (appConnection.state === signalR.HubConnectionState.Connected) {
				appConnection.invoke('LeaveCrew', crewID).catch(() => {});
			}
		};
	}, [appConnection, appConnected, crewID, fetchMembers]);

	// SignalR presence 구독 — 멤버 목록 변경 시 재구독, 이벤트 수신 시 isOnline 갱신.
	// members 가 빈 배열일 때는 구독할 대상이 없어 early return — 첫 fetchMembers 완료 후 의존성 변화로 재실행되어 정상 구독.
	const memberIDsKey = members.map(m => m.memberID).join(',');

	useEffect(() => {
		if (!appConnection || !appConnected) {
			return;
		}

		if (appConnection.state !== signalR.HubConnectionState.Connected) {
			return;
		}

		const memberIDs = Array.from(new Set(members.map(m => m.memberID))).filter(id => id > 0);
		if (memberIDs.length === 0) {
			return;
		}

		const handler = (memberID: number, isOnline: boolean) => {
			setMembers(prev => prev.map(m => m.memberID === memberID ? { ...m, isOnline } : m));
		};

		appConnection.on('ReceivePresenceChange', handler);
		appConnection.invoke('SubscribePresence', memberIDs).catch(err => {
			console.warn('[presence] SubscribePresence failed:', err);
		});

		return () => {
			appConnection.off('ReceivePresenceChange', handler);

			if (appConnection.state === signalR.HubConnectionState.Connected) {
				appConnection.invoke('UnsubscribePresence', memberIDs).catch(() => {});
			}
		};
	// memberIDsKey 가 동일하면 effect 재실행 안됨 (불필요한 sub/unsub 방지).
	// members 자체를 의존성에 넣지 않는 이유: members 가 같은 ID 집합이어도 객체 reference 가 바뀌면 매번 재실행되므로.
	// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [appConnection, appConnected, memberIDsKey]);

	// 회원 검색 (디바운스)
	useEffect(() => {
		if (searchTimer.current) {
			clearTimeout(searchTimer.current);
		}

		if (searchQuery.trim().length < 2) {
			setSearchResults([]);
			return;
		}

		searchTimer.current = setTimeout(async () => {
			try {

				const res = await fetchApi<SearchMemberResponse>(
					`/api/studio/crew/member/search?channelID=${channelID}&q=${encodeURIComponent(searchQuery)}&crewID=${crewID}`
				);

				setSearchResults(res.data?.list ?? []);
			} catch {}
		}, 300);

		return () => {
			if (searchTimer.current) {
				clearTimeout(searchTimer.current);
			}
		};
	}, [searchQuery, channelID, crewID]);

	const handleAddMember = async (item: SearchResultItem) => {
		try {

			await fetchApi('/api/studio/crew/member/add', {
				method: 'POST',
				body: {
					crewID,
					targetMemberID: item.memberID,
					nickname: item.channelName ?? item.name ?? item.email,
					sortOrder: members.length + 1
				}
			});

			setSearchQuery('');
			setSearchResults([]);
			setShowSearch(false);
			fetchMembers();

		} catch (err: unknown) {
			alert(err instanceof Error ? err.message : '추가에 실패했습니다.');
		}
	};

	const handleRemove = async (memberID: number) => {
		if (!confirm('이 크루원을 삭제하시겠습니까?')) {
			return;
		}

		try {

			await fetchApi(`/api/studio/crew/member/${memberID}`, { method: 'DELETE' });
			fetchMembers();

		} catch (err: unknown) {
			alert(err instanceof Error ? err.message : '삭제에 실패했습니다.');
		}
	};

	const openEdit = (member: CrewMemberItem) => {
		setEditForm({ nickname: member.nickname, role: member.role ?? '', sortOrder: member.sortOrder, isActive: member.isActive });
		setEditModal({ open: true, member });
	};

	const handleUpdate = async () => {
		if (!editModal.member) {
			return;
		}

		setSaving(true);

		try {

			await fetchApi(`/api/studio/crew/member/${editModal.member.id}`, {
				method: 'PUT',
				body: {
					crewMemberID: editModal.member.id,
					nickname: editForm.nickname,
					role: editForm.role || null,
					sortOrder: editForm.sortOrder,
					isActive: editForm.isActive
				}
			});

			setEditModal({ open: false, member: null });
			fetchMembers();
		} catch (err: unknown) {
			alert(err instanceof Error ? err.message : '수정에 실패했습니다.');
		} finally {
			setSaving(false);
		}
	};

	const handleGenerateCode = async () => {
		setGeneratingCode(true);

		try {

			const res = await fetchApi<{ inviteCode: string }>('/api/studio/crew/invite/generate', {
				method: 'POST',
				body: { crewID }
			});

			setInviteCode(res.data?.inviteCode ?? null);

		} catch (err: unknown) {
			alert(err instanceof Error ? err.message : '코드 생성에 실패했습니다.');
		} finally {
			setGeneratingCode(false);
		}
	};

	const copyCode = () => {
		if (inviteCode) {
			navigator.clipboard.writeText(inviteCode);
			alert('복사되었습니다.');
		}
	};

	if (loading) return <p className="studio-page__empty">준비 중...</p>;

	return (
		<>
			{/* 초대 코드 */}
			<fieldset className="crew-invite">
				<legend className="crew-invite__legend">
					<span>초대 코드</span>
					<TooltipProvider delay={0}>
						<Tooltip>
							<TooltipTrigger
								render={
									<button type="button" className="crew-invite__help" aria-label="초대 코드 안내">
										<Info size={14} aria-hidden="true" />
									</button>
								}
							/>
							<TooltipContent side="top" align="start">
								이 코드를 입력한 회원은 크루 방송 합류에 동의하는 것으로 처리됩니다.<br />
								입력 페이지: /crew/join
							</TooltipContent>
						</Tooltip>
					</TooltipProvider>
				</legend>
				<div className="crew-invite__body">
					<Input
						readOnly
						value={inviteCode ?? ''}
						placeholder="코드를 생성해 주세요"
						className="crew-invite__input"
					/>
					<div className="crew-invite__actions">
						{inviteCode ? (
							<>
								<Button type="button" variant="outline" onClick={copyCode}>복사</Button>
								<Button type="button" variant="outline" onClick={handleGenerateCode} disabled={generatingCode}>
									{generatingCode ? '생성 중...' : '재생성'}
								</Button>
							</>
						) : (
							<Button type="button" onClick={handleGenerateCode} disabled={generatingCode}>
								{generatingCode ? '생성 중...' : '코드 생성'}
							</Button>
						)}
					</div>
				</div>
			</fieldset>

			{/* 크루원 관리 */}
			<div className="crew-members">
				<div className="crew-members__toolbar pb-3">
					<h2 className="crew-members__subtitle">크루원 ({members.length}명)</h2>
					<Button size="sm" onClick={() => setShowSearch(!showSearch)}>
						{showSearch ? '닫기' : '+ 크루원 추가'}
					</Button>
				</div>

				{showSearch && (
					<div className="member-search mb-4">
						<Input className="member-search__input" placeholder="채널명, 핸들, 이메일로 검색 (2자 이상)" value={searchQuery} onChange={e => setSearchQuery(e.target.value)} autoComplete='off'/>
						{searchResults.length > 0 && (
							<div className="member-search__results">
								{searchResults.map(item => (
									<button type="button" key={item.memberID} className="member-search__item" onClick={() => handleAddMember(item)}>
										{item.channelThumb ? <img src={item.channelThumb} alt="" className="member-search__thumb" /> : <div className="member-search__thumb" />}
										<div className="member-search__info">
											<div className="member-search__name">{item.channelName ?? item.name ?? '(이름 없음)'}</div>
											<div className="member-search__email">{item.email}</div>
											{item.channelHandle && (
												<div className="member-search__handle">@{item.channelHandle}</div>
											)}
										</div>
									</button>
								))}
							</div>
						)}
					</div>
				)}

				<div className="studio-page__table-wrap">
					<table className="studio-page__table">
						<thead>
							<tr>
								<th>순서</th>
								<th>별명</th>
								<th>역할</th>
								<th>채널</th>
								<th>접속</th>
								<th>상태</th>
								<th>가입일</th>
								<th>작업</th>
							</tr>
						</thead>
						<tbody>
							{members.length === 0 ? (
								<tr><td colSpan={8} className="studio-page__empty">등록된 크루원이 없습니다.</td></tr>
							) : members.map(m => {
								const isAccepted = m.inviteStatus === 'Accepted';
								const statusLabel = m.inviteStatus === 'Accepted'
									? (m.isActive ? '활성' : '비활성')
									: m.inviteStatus === 'Pending' ? '초대 중'
									: m.inviteStatus === 'Declined' ? '거절됨'
									: '만료';
								const statusModifier = m.inviteStatus === 'Accepted'
									? (m.isActive ? 'active' : 'inactive')
									: m.inviteStatus === 'Pending' ? 'pending'
									: 'expired';
								return (
									<tr key={m.id}>
										<td>{m.sortOrder}</td>
										<td>
											<Avatar className="member-row__thumb">
												<AvatarImage src={(m.channelThumb ?? m.thumb) || undefined} alt={m.nickname} />
												<AvatarFallback className="member-row__thumb-fallback p-1">
													<img src="/icons/layout/avatar.svg" alt={m.nickname} />
												</AvatarFallback>
											</Avatar>
											{m.nickname}
										</td>
										<td>{m.role ?? '-'}</td>
										<td>{m.channelName ?? '-'}</td>
										<td>
											<span
												className={`member-row__online-dot${m.isOnline ? ' member-row__online-dot--on' : ''}`}
												title={m.isOnline ? '온라인' : '오프라인'}
												aria-label={m.isOnline ? '온라인' : '오프라인'}
											/>
										</td>
										<td><span className={`studio-page__badge studio-page__badge--${statusModifier}`}>{statusLabel}</span></td>
										<td>{new Date(m.joinedAt).toLocaleDateString('ko-KR')}</td>
										<td>
											<div className="studio-page__actions">
												{isAccepted ? (
													<>
														<Button variant="outline" size="sm" onClick={() => openEdit(m)}>수정</Button>
														<Button variant="destructive" size="sm" onClick={() => handleRemove(m.id)}>삭제</Button>
													</>
												) : (
													<span className="text-xs text-muted-foreground">{m.inviteStatus === 'Pending' ? '응답 대기' : '-'}</span>
												)}
											</div>
										</td>
									</tr>
								);
							})}
						</tbody>
					</table>
				</div>
			</div>

			{/* 크루원 편집 모달 */}
			<Dialog open={editModal.open} onOpenChange={open => { if (!open) setEditModal({ open: false, member: null }); }}>
				<DialogContent>
					<DialogHeader>
						<DialogTitle>크루원 수정</DialogTitle>
					</DialogHeader>
					<div className="space-y-4">
						<div className="space-y-2">
							<RequiredLabel htmlFor="member-nickname">별명</RequiredLabel>
							<Input id="member-nickname" value={editForm.nickname} onChange={e => setEditForm(f => ({ ...f, nickname: e.target.value }))} />
						</div>
						<div className="space-y-2">
							<Label htmlFor="member-role">역할</Label>
							<Input id="member-role" value={editForm.role} onChange={e => setEditForm(f => ({ ...f, role: e.target.value }))} placeholder="예: 게이머, MC" />
						</div>
						<div className="space-y-2">
							<Label htmlFor="member-order">순서</Label>
							<Input id="member-order" type="number" min={0} value={editForm.sortOrder} onChange={e => setEditForm(f => ({ ...f, sortOrder: Number(e.target.value) }))} />
						</div>
						<div className="flex items-center gap-2">
							<Checkbox id="member-active" checked={editForm.isActive} onCheckedChange={v => setEditForm(f => ({ ...f, isActive: !!v }))} />
							<Label htmlFor="member-active">활성화</Label>
						</div>
					</div>
					<DialogFooter className="flex flex-row justify-center gap-2 sm:justify-center">
						<Button variant="outline" className="flex-1 sm:flex-none" onClick={() => setEditModal({ open: false, member: null })}>취소</Button>
						<Button className="flex-1 sm:flex-none" onClick={handleUpdate} disabled={saving}>{saving ? '저장 중...' : '저장'}</Button>
					</DialogFooter>
				</DialogContent>
			</Dialog>
		</>
	);
}